package de.blinkt.openvpn.advancedsettings2;

import java.io.Serializable;

import android.app.Activity;
import android.content.Context;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import de.blinkt.openvpn.NetworkUtil;
import de.blinkt.openvpn.ProfileManager;
import de.blinkt.openvpn.R;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.VpnProfile.VpnNetworkInfo;
import de.blinkt.openvpn.advancedsettings2.ConfigureNetworkItemPresenter.ConfigureNetworkItemFinishedCallback;

public class AdvancedSettingsPresenter implements ConfigureNetworkItemFinishedCallback {

	private AdvancedSettingsView mView;
	private VpnProfile mProfile;
	private ArrayAdapter<NetworkListItem> mModel;
	private Activity mActivity;
	private int mCurrentlySelectedItemPosition;

	public AdvancedSettingsPresenter(AdvancedSettingsView view) {
		mView = view;
	}

	public void loadModelFromStorage(Activity activity, String profileUUID) {
		mActivity = activity;
		mProfile = ProfileManager.get(profileUUID);
		if(mProfile == null){
			mProfile = new VpnProfile("");
		} 
		
		mModel = new ArrayAdapter<NetworkListItem>(mActivity, android.R.layout.simple_list_item_1);
	}
	
	public void loadModelFromSavedState(Activity activity, Bundle savedInstanceState) {
		mActivity = activity;
		mProfile = ProfileManager.get(savedInstanceState.getString(mActivity.getPackageName() + "profileUUID"));		
		mModel = new ArrayAdapter<NetworkListItem>(mActivity, android.R.layout.simple_list_item_1);
		
		mCurrentlySelectedItemPosition = savedInstanceState.getInt("selectionPosition");
	}
	
	public void saveModel(Bundle outState) {
		if(mProfile!=null) {
			outState.putString(mActivity.getPackageName() + "profileUUID", mProfile.getUUID().toString());
			outState.putInt("selectionPosition", mCurrentlySelectedItemPosition);
		}
	}

	public void populateViewFromProfile() {
		mActivity.setTitle(mActivity.getResources().getString(R.string.edit_profile_title, mProfile.getName()));

		mView.getRestrictToNetworks().setChecked(mProfile.mRestrictReconnectToNetworks);
		setViewForRestrictNetwork(mProfile.mRestrictReconnectToNetworks);
		
		mModel.clear();
		
		for (VpnNetworkInfo network : mProfile.mRestrictedNetworksList) {
			NetworkListItem li = new NetworkListItem(network.mNetworkType, network.mNetworkTypeName, network.mNetworkSubtype, network.mNetworkSubtypeName, network.mNetworkName, network.mAssociatedNetworkSettings.mProxyType, network.mAssociatedNetworkSettings.mProxyServerAddress, network.mAssociatedNetworkSettings.mProxyServerPort, network.mAssociatedNetworkSettings.mProxyIndefiniteRetry); 
			mModel.add(li);
		}
		
		mView.getNetworkList().setAdapter(mModel);
		mView.getAddCurrentButton().setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				addCurrentNetworkPressed(mActivity);
			}
		});
		
		mView.getRestrictToNetworks().setOnCheckedChangeListener(new OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				setViewForRestrictNetwork(isChecked);
			}
		});
		
		mView.getNetworkList().setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				networkClicked(position);
			}
		});
	}
	
	protected void networkClicked(int position) {
		
		ConfigureNetworkItemPresenter presenter = new ConfigureNetworkItemPresenter();
		ConfigureNetworkItemView view = mView.showConfigureNetworkItemView();
		presenter.setActivity(mActivity);
		presenter.setView(view);
		view.setPresenter(presenter);
		mCurrentlySelectedItemPosition = position;

	}

	protected void setViewForRestrictNetwork(boolean isChecked) {
//		mView.getAddCurrentButton().setEnabled(isChecked);
//		mView.getNetworkList().setEnabled(isChecked);
	}

	protected void addCurrentNetworkPressed(Context c) {
		// TODO: Better model is to use network state receiver to listen for
		// network changes to ensure currently connectect
		// and enable/disable add button based on that value

		// attach to connectivity manager
		NetworkInfo activeNetworkInfo = NetworkUtil.getCurrentNetworkInfo(mActivity);
		
		try {
			if (activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting()) {
				
				String networkName = NetworkUtil.extractNetworkName(mActivity, activeNetworkInfo);
				boolean exists = false;
				for(int i = 0; i < mModel.getCount(); i++){
					NetworkListItem item = mModel.getItem(i);
					if(item.getType() == activeNetworkInfo.getType() && item.getSubtype() == activeNetworkInfo.getSubtype() && networkName.equals(item.getName())){
						exists = true;
					}
				}

				if(exists){
					mView.showNetworkAlreadyExistsError();
				} else {
					NetworkListItem newItem = new NetworkListItem(activeNetworkInfo.getType(), activeNetworkInfo.getTypeName(), activeNetworkInfo.getSubtype(),  activeNetworkInfo.getSubtypeName(), "UNKNOWN", null, null, 0, false);
					newItem.setName(networkName);
					mModel.add(newItem);
				}
				
			} else {
				mView.showNotConnectedToNetworkError();

			}
		} catch (IllegalArgumentException e) {
			mView.showUnableToAddNetworkError();
		}
		
	}
	
	public void saveViewToProfile() {
		mProfile.mRestrictReconnectToNetworks = mView.getRestrictToNetworks().isChecked();
		
		mProfile.mRestrictedNetworksList = new VpnProfile.VpnNetworkInfo[mModel.getCount()];
		for(int  i = 0; i < mModel.getCount(); i++){
			VpnProfile.VpnNetworkInfo networkInfo = new VpnProfile.VpnNetworkInfo();
			networkInfo.mNetworkName = mModel.getItem(i).getName();
			networkInfo.mNetworkType = mModel.getItem(i).getType();
			networkInfo.mNetworkSubtype = mModel.getItem(i).getSubtype();
			networkInfo.mNetworkTypeName = mModel.getItem(i).getTypeName();
			networkInfo.mNetworkSubtypeName = mModel.getItem(i).getSubtypeName();
			networkInfo.mAssociatedNetworkSettings.mProxyType = mModel.getItem(i).getProxyType();
			networkInfo.mAssociatedNetworkSettings.mProxyServerPort = mModel.getItem(i).getProxyServerPort();
			networkInfo.mAssociatedNetworkSettings.mProxyServerAddress = mModel.getItem(i).getProxyServerAddress();
			networkInfo.mAssociatedNetworkSettings.mProxyIndefiniteRetry = mModel.getItem(i).getIndefiniteRetry();
			
			mProfile.mRestrictedNetworksList[i] = networkInfo;
		}
		 
	}


	static class NetworkListItem implements Serializable {
		
		private static final long serialVersionUID = 1L;
		
		private int mType;
		private int mSubtype;
		private String mName;
		private String mTypeName;
		private String mSubtypeName;
		private String mProxyType;
		private String mProxyServerAddress;
		private int mProxyServerPort;
		private boolean mIndefiniteRetry;

		public NetworkListItem(int type, String typeName, int subtype, String subtypeName, String name, String proxyType, String address, int port, boolean indefiniteRetry){
			mType = type;
			mSubtype = subtype;
			mName = name;
			mTypeName = typeName;
			mSubtypeName = subtypeName;
			mProxyType = proxyType;
			mProxyServerAddress = address;
			mProxyServerPort = port;
			mIndefiniteRetry = indefiniteRetry;
		}

		public boolean getIndefiniteRetry() {
			return mIndefiniteRetry;
		}

		public int getType() {
			return mType;
		}

		public int getSubtype() {
			return mSubtype;
		}

		public String getName() {
			return mName;
		}
		
		public void setName(String name) {
			mName = name;
		}

		public String getTypeName() {
			return mTypeName;
		}
		public String getSubtypeName() {
			return mSubtypeName;
		}
		
		public String toString() {
			return mTypeName +  (mSubtypeName != null && mSubtypeName.length() > 0 ? ( " ( " + mSubtypeName + " ) ") : "") + " - " + mName; 
		}

		public String getProxyType() {
			return mProxyType;
		}

		public void setProxyType(String proxyType) {
			mProxyType = proxyType;
			
		}
		
		public String getProxyServerAddress() {
			return mProxyServerAddress;
		}
		
		public void setProxyServerAddress(String proxyServerAddress) {
			mProxyServerAddress = proxyServerAddress;
		}
		
		public int getProxyServerPort() {
			return mProxyServerPort;
		}
		public void setProxyServerPort(int proxyServerPort) {
			mProxyServerPort = proxyServerPort;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + (mIndefiniteRetry ? 1231 : 1237);
			result = prime * result + ((mName == null) ? 0 : mName.hashCode());
			result = prime * result + ((mProxyServerAddress == null) ? 0 : mProxyServerAddress.hashCode());
			result = prime * result + mProxyServerPort;
			result = prime * result + ((mProxyType == null) ? 0 : mProxyType.hashCode());
			result = prime * result + mSubtype;
			result = prime * result + ((mSubtypeName == null) ? 0 : mSubtypeName.hashCode());
			result = prime * result + mType;
			result = prime * result + ((mTypeName == null) ? 0 : mTypeName.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			NetworkListItem other = (NetworkListItem) obj;
			if (mIndefiniteRetry != other.mIndefiniteRetry)
				return false;
			if (mName == null) {
				if (other.mName != null)
					return false;
			} else if (!mName.equals(other.mName))
				return false;
			if (mProxyServerAddress == null) {
				if (other.mProxyServerAddress != null)
					return false;
			} else if (!mProxyServerAddress.equals(other.mProxyServerAddress))
				return false;
			if (mProxyServerPort != other.mProxyServerPort)
				return false;
			if (mProxyType == null) {
				if (other.mProxyType != null)
					return false;
			} else if (!mProxyType.equals(other.mProxyType))
				return false;
			if (mSubtype != other.mSubtype)
				return false;
			if (mSubtypeName == null) {
				if (other.mSubtypeName != null)
					return false;
			} else if (!mSubtypeName.equals(other.mSubtypeName))
				return false;
			if (mType != other.mType)
				return false;
			if (mTypeName == null) {
				if (other.mTypeName != null)
					return false;
			} else if (!mTypeName.equals(other.mTypeName))
				return false;
			return true;
		}
	}

	@Override
	public void saved() {
		mCurrentlySelectedItemPosition = -1;
	}

	@Override
	public void cancelled() {
		mCurrentlySelectedItemPosition = -1;
	}

	@Override
	public void removedNetwork() {
		mModel.remove(mModel.getItem(mCurrentlySelectedItemPosition));
		mCurrentlySelectedItemPosition = -1;
	}

	public NetworkListItem getCurrentlySelectedItem() {
		return mModel.getItem(mCurrentlySelectedItemPosition);
	}
	
}
